home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 1: Comms & Networking / Almathera Ten on Ten - Disc 1: Comms & Networking.iso / tools / archie / archie-1.4 / aquery.c next >
C/C++ Source or Header  |  1995-05-01  |  9KB  |  309 lines

  1. /*
  2.  * aquery.c : Programmatic Prospero interface to Archie
  3.  *
  4.  * Copyright (c) 1991 by the University of Washington
  5.  *
  6.  * For copying and distribution information, please see the file
  7.  * <copyright.h>.
  8.  */
  9. /* Amiga port by Tomas Willis (tomas@cae.wisc.edu) January 1995 */
  10.  
  11. #include <stdio.h>
  12.  
  13. #include "pfs.h"
  14. #include "perrno.h"
  15. #include "archie.h"
  16.  
  17. #include "pmachine.h"
  18. #ifdef NEED_STRING_H
  19. # include <string.h>            /* for char *index() */
  20. #else
  21. # include <strings.h>            /* for char *index() */
  22. #endif
  23.  
  24. #ifdef __GNUC__
  25. #define INLINE __inline__
  26. #else
  27. #define INLINE
  28. #endif
  29.  
  30.  
  31. extern int pwarn;
  32. extern char p_warn_string[];
  33. extern int get_vdir(char *dhost, char *dfile, char *components, PVDIR dir, long flags,
  34.                     VLINK filters, char *acomp);
  35.  
  36. //protos
  37. VLINK archie_query(char *host, char *string, int max_hits,int offset, Query
  38.     query,int (*cmp_proc)(VLINK p, VLINK q),int flags);
  39. int invdatecmplink(VLINK p, VLINK q);
  40. int defcmplink( VLINK p, VLINK q);
  41. static void translateArchieResponse(VLINK);
  42. INLINE static int hostnamecmp(char *, char *);
  43. //extern
  44. extern char * stcopyr(char *s, char *r);
  45.  
  46.  
  47. /*
  48.  * archie_query : Sends a request to _host_, telling it to search for
  49.  *                _string_ using _query_ as the search method.
  50.  *                No more than _max_hits_ matches are to be returned
  51.  *                skipping over _offset_ matches.
  52.  *
  53.  *          archie_query returns a linked list of virtual links.
  54.  *                If _flags_ does not include AQ_NOTRANS, then the Archie
  55.  *                responses will be translated. If _flags_ does not include
  56.  *                AQ_NOSORT, then the list will be sorted using _cmp_proc_ to
  57.  *                compare pairs of links.  If _cmp_proc_ is NULL or AQ_DEFCMP,
  58.  *                then the default comparison procedure, defcmplink(), is used
  59.  *                sorting by host, then filename. If cmp_proc is AQ_INVDATECMP
  60.  *                then invdatecmplink() is used, sorting inverted by date.
  61.  *                otherwise a user-defined comparison procedure is called.
  62.  *
  63.  *                archie_query returns NULL and sets perrno if the query
  64.  *                failed. Note that it can return NULL with perrno == PSUCCESS
  65.  *                if the query didn't fail but there were simply no matches.
  66.  *
  67.  *        query:  S  Substring search ignoring case   
  68.  *                C  Substring search with case significant
  69.  *                R  Regular expression search
  70.  *                =  Exact String Match
  71.  *            s,c,e  Tries exact match first and falls back to S, C, or R 
  72.  *                   if not found.
  73.  *
  74.  *     cmp_proc:  AQ_DEFCMP      Sort by host, then filename
  75.  *                AQ_INVDATECMP  Sort inverted by date
  76.  *
  77.  *        flags:  AQ_NOSORT      Don't sort results
  78.  *                AQ_NOTRANS     Don't translate results
  79.  */
  80. VLINK
  81. archie_query(char *host, char *string, int max_hits,int offset,
  82.     Query query, int (*cmp_proc)(VLINK p, VLINK q), int flags)
  83. //    char    *host,*string;
  84. //    int        max_hits,offset;
  85. //    Query    query;
  86. //    int        (*cmp_proc)();
  87. //    int        flags;
  88. {
  89.     char qstring[MAX_VPATH];    /* For construting the query  */
  90.     VLINK    links;        /* Matches returned by server */
  91.     VDIR_ST    dir_st;         /* Filled in by get_vdir      */
  92.     PVDIR    dir= &dir_st;
  93.  
  94.     VLINK    p,q,r,lowest,nextp,pnext,pprev;
  95.     int    tmp;
  96.  
  97.     /* Set the cmp_proc if not given */
  98.     if (cmp_proc == NULL) cmp_proc = defcmplink;
  99.  
  100.     /* Make the query string */
  101.     sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
  102.         max_hits,offset, (char) query,string);
  103.  
  104.     /* Initialize Prospero structures */
  105.     perrno = PSUCCESS; *p_err_string = '\0';
  106.     pwarn = PNOWARN; *p_warn_string = '\0';
  107.     vdir_init(dir);
  108.  
  109.     /* Retrieve the list of matches, return error if there was one */
  110. #if defined(MSDOS)
  111.     if(tmp = get_vdir(host, qstring, "", dir, (long)GVD_ATTRIB|GVD_NOSORT, NULL, NULL)) {
  112. #else
  113.     if(tmp = get_vdir(host, qstring, "", dir, GVD_ATTRIB|GVD_NOSORT, NULL, NULL)) {
  114. # endif
  115.         perrno = tmp;
  116.         return(NULL);
  117.     }
  118.  
  119.     /* Save the links, and clear in dir in case it's used again   */
  120.     links = dir->links; dir->links = NULL;
  121.  
  122.     /* As returned, list is sorted by suffix, and conflicting     */
  123.     /* suffixes appear on a list of "replicas".  We want to       */
  124.     /* create a one-dimensional list sorted by host then filename */
  125.     /* and maybe by some other parameter                          */
  126.  
  127.     /* First flatten the doubly-linked list */
  128.     for (p = links; p != NULL; p = nextp) {
  129.         nextp = p->next;
  130.         if (p->replicas != NULL) {
  131.         p->next = p->replicas;
  132.         p->next->previous = p;
  133.         for (r = p->replicas; r->next != NULL; r = r->next)
  134.             /*EMPTY*/ ;
  135.         r->next = nextp;
  136.         nextp->previous = r;
  137.         p->replicas = NULL;
  138.         }
  139.     }
  140.  
  141.     /* Translate the filenames unless NOTRANS was given */
  142.     if (!(flags & AQ_NOTRANS))
  143.         for (p = links; p != NULL; p = p->next)
  144.         translateArchieResponse(p);
  145.  
  146.     /* If NOSORT given, then just hand it back */
  147.     if (flags & AQ_NOSORT) {
  148.         perrno = PSUCCESS;
  149.         return(links);
  150.     }
  151.  
  152.     /* Otherwise sort it using a selection sort and the given cmp_proc */
  153.     for (p = links; p != NULL; p = nextp) {
  154.         nextp = p->next;
  155.         lowest = p;
  156.         for (q = p->next; q != NULL; q = q->next)
  157.         if ((*cmp_proc)(q,lowest) < 0)
  158.             lowest = q;
  159.         if (p != lowest) {
  160.         /* swap the two links */
  161.         pnext = p->next;
  162.         pprev = p->previous;
  163.         if (lowest->next != NULL)
  164.             lowest->next->previous = p;
  165.         p->next = lowest->next;
  166.         if (nextp == lowest) {
  167.             p->previous = lowest;
  168.         } else {
  169.             lowest->previous->next = p;
  170.             p->previous = lowest->previous;
  171.         }
  172.         if (nextp == lowest) {
  173.             lowest->next = p;
  174.         } else {
  175.             pnext->previous = lowest;
  176.             lowest->next = pnext;
  177.         }
  178.         if (pprev != NULL)
  179.             pprev->next = lowest;
  180.         lowest->previous = pprev;
  181.         /* keep the head of the list in the right place */
  182.         if (links == p)
  183.             links = lowest;
  184.         }
  185.     }
  186.  
  187.     /* Return the links */
  188.     perrno = PSUCCESS;
  189.     return(links);
  190. }
  191.  
  192. /*
  193.  * translateArchieResponse: 
  194.  *
  195.  *   If the given link is for an archie-pseudo directory, fix it. 
  196.  *   This is called unless AQ_NOTRANS was given to archie_query().
  197.  */
  198. static void
  199. translateArchieResponse(VLINK l)
  200. //    VLINK l;
  201.     {
  202.     char *slash;
  203.  
  204.     if (strcmp(l->type,"DIRECTORY") == 0) {
  205.         if (strncmp(l->filename,"ARCHIE/HOST",11) == 0) {
  206.         l->type = stcopyr("EXTERNAL(AFTP,DIRECTORY)",l->type);
  207.         l->host = stcopyr(l->filename+12,l->host);
  208.         slash = (char *)index(l->host,'/');
  209.         if (slash) {
  210.             l->filename = stcopyr(slash,l->filename);
  211.             *slash++ = '\0';
  212.         } else
  213.             l->filename = stcopyr("",l->filename);
  214.         }
  215.     }
  216.     }
  217.  
  218.  
  219. /* hostnamecmp: Compare two hostnames based on domain,
  220.  *              right-to-left.  Returns <0 if a belongs before b, >0
  221.  *              if b belongs before a, and 0 if they are identical.
  222.  *              Contributed by asami@cs.berkeley.edu (Satoshi ASAMI).
  223.  */
  224. INLINE
  225. static int
  226. hostnamecmp(char *a, char *b)
  227. //    char *a,*b;
  228.     {
  229.     char    *pa, *pb;
  230.     int    result;
  231.  
  232.     for (pa = a ; *pa ; pa++)
  233.         ;
  234.     for (pb = b ; *pb ; pb++)
  235.         ;
  236.  
  237.     while (pa > a && pb > b) {
  238.         for (; pa > a ; pa--)
  239.         if (*pa == '.')    {
  240.             pa++;
  241.             break;
  242.         }
  243.         for (; pb > b ; pb--)
  244.         if (*pb == '.')    {
  245.             pb++;
  246.             break;
  247.         }
  248.         if (result = strcmp(pa, pb))
  249.         return (result);
  250.         pa -= 2;
  251.         pb -= 2;
  252.     }
  253.     if (pa <= a) {
  254.         if (pb <= b)
  255.         return (0);
  256.         else
  257.         return (-1);
  258.     } else
  259.         return (1);
  260.     }
  261.  
  262. /*
  263.  * defcmplink: The default link comparison function for sorting. Compares
  264.  *           links p and q first by host then by filename. Returns < 0 if p
  265.  *             belongs before q, > 0 if p belongs after q, and == 0 if their
  266.  *             host and filename fields are identical.
  267.  */
  268. int
  269. defcmplink( VLINK p, VLINK q)
  270. //    VLINK p,q;
  271.     {
  272.     int result;
  273.  
  274.     if ((result=hostnamecmp(p->host,q->host)) != 0)
  275.         return(result);
  276.     else
  277.         return(strcmp(p->filename,q->filename));
  278.     }
  279.  
  280. /*
  281.  * invdatecmplink: An alternative comparison function for sorting that
  282.  *               compares links p and q first by LAST-MODIFIED date,
  283.  *                 if they both have that attribute. If both links
  284.  *                 don't have that attribute or the dates are the
  285.  *                 same, it then calls defcmplink() and returns its
  286.  *           value.
  287.  */
  288. int
  289. invdatecmplink(VLINK p, VLINK q)
  290. //    VLINK p,q;
  291. {
  292.     PATTRIB pat,qat;
  293.     char *pdate,*qdate;
  294.     int result;
  295.  
  296.     pdate = qdate = NULL;
  297.     for (pat = p->lattrib; pat; pat = pat->next)
  298.         if(strcmp(pat->aname,"LAST-MODIFIED") == 0)
  299.         pdate = pat->value.ascii;
  300.     for (qat = q->lattrib; qat; qat = qat->next)
  301.         if(strcmp(qat->aname,"LAST-MODIFIED") == 0)
  302.         qdate = qat->value.ascii;
  303.     if(!pdate && !qdate) return(defcmplink(p,q));
  304.     if(!pdate) return(1);
  305.     if(!qdate) return(-1);
  306.     if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q));
  307.     else return(result);
  308. }
  309.